package com.xiaoshuidi.cloud.module.finance.mq;

import org.springframework.boot.context.event.ApplicationContextInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.*;

import java.util.HashMap;
import java.util.Map;

public class LeaseFinanceEnvironmentPostProcessor implements ApplicationListener<ApplicationContextInitializedEvent> {
    static final String OVERRIDES_PROPERTY_SOURCE_NAME = "leaseFinanceOverridesProperties";
    private static final String FN_DEF_PROP = "spring.cloud.stream.function.definition";

    public void postProcessEnvironment(ConfigurableEnvironment environment) {
        if (environment.containsProperty("lease.finance.pay-notify.enabled")) {
            if (Boolean.FALSE.toString()
                    .equalsIgnoreCase(environment.getProperty("lease.finance.pay-notify.enabled"))) {
                return;
            }
        }
        String profile = environment.getProperty("spring.profiles.active");

        Map<String, Object> overrides = new HashMap<>();
        String definition = PayResultConstants.CONSUMER;
        if (environment.containsProperty(FN_DEF_PROP)) {
            String property = environment.getProperty(FN_DEF_PROP);
            if (property != null && property.contains(PayResultConstants.CONSUMER)) {
                // in the case that EnvironmentPostProcessor are run more than once.
                return;
            }
            definition = property + ";" + definition;
        }
        overrides.put(FN_DEF_PROP, definition);
        String applicationName = environment.getProperty("spring.application.name");
        overrides.put("spring.cloud.stream.function.bindings." + PayResultConstants.CONSUMER + "-in-0",
                PayResultConstants.INPUT);
        overrides.put("spring.cloud.stream.bindings." + PayResultConstants.INPUT + ".destination", PayResultConstants.DESTINATION);
        overrides.put("spring.cloud.stream.bindings." + PayResultConstants.INPUT + ".group", "pay-result-group-" + applicationName);
        overrides.put("spring.cloud.stream.rocketmq.bindings." + PayResultConstants.INPUT + ".consumer.group", "pay-result-group-" + applicationName);
        overrides.put("spring.cloud.stream.bindings." + PayResultConstants.OUTPUT + ".destination", PayResultConstants.DESTINATION);
        if ("dev".equals(profile)) {
            String localip = environment.getProperty("spring.cloud.client.ip-address").replaceAll("\\.", "");
            overrides.put("spring.cloud.stream.bindings." + PayResultConstants.OUTPUT + ".destination", localip + "%" + PayResultConstants.DESTINATION);
            overrides.put("spring.cloud.stream.bindings." + PayResultConstants.INPUT + ".destination", localip + "%" + PayResultConstants.DESTINATION);
            overrides.put("spring.cloud.stream.rocketmq.bindings." + PayResultConstants.INPUT + ".consumer.namespace", localip);
        }
        addOrReplace(environment.getPropertySources(), overrides, OVERRIDES_PROPERTY_SOURCE_NAME, true);
    }

    public static void addOrReplace(MutablePropertySources propertySources, Map<String, Object> map,
                                    String propertySourceName, boolean first) {
        MapPropertySource target = null;
        if (propertySources.contains(propertySourceName)) {
            PropertySource<?> source = propertySources.get(propertySourceName);
            if (source instanceof MapPropertySource) {
                target = (MapPropertySource) source;
                target.getSource().putAll(map);
            }
        }
        if (target == null) {
            target = new MapPropertySource(propertySourceName, map);
        }
        if (propertySources.contains(propertySourceName)) {
            propertySources.remove(propertySourceName);
        }
        if (first) {
            propertySources.addFirst(target);
        } else {
            propertySources.addLast(target);
        }
    }

    @Override
    public void onApplicationEvent(ApplicationContextInitializedEvent event) {
        Environment environment = event.getApplicationContext().getEnvironment();
        postProcessEnvironment((ConfigurableEnvironment) environment);
    }
}
